package git

import (
	"context"
	"gitee.com/kmyss/gf-ex/yscmd"
	"gitee.com/kmyss/gf-ex/yslog"
	"gitee.com/kmyss/gf-ex/ysutils"
	"gitee.com/kmyss/gf-ex/ysview"
	"gitee.com/kmyss/ys-cli/internal/consts"
	"gitee.com/kmyss/ys-cli/internal/model"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gfile"
	"github.com/gogf/gf/v2/os/gproc"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"os"
)

const (
	statusStaged    = "staged"    // 已暂存的
	statusChanged   = "changed"   // 有修改的
	statusUntracked = "untracked" // 未跟踪的
)

// branchSelect 选择的branch
func (s *sGit) branchSelect(ctx context.Context) (out string, err error) {
	branches, err := s.branches(ctx)
	if err != nil {
		return
	}

	b := make([]string, 0, len(branches))
	for _, name := range branches {
		b = append(b, gfile.Basename(name))
	}

	out, _ = yscmd.SelectOne(b, "请选择分支")
	return
}

// 获取分支列表，当前分支放在第一位
func (s *sGit) branches(ctx context.Context) (out []string, err error) {

	raw, err := gproc.ShellExec(ctx, "git branch")
	if err != nil {
		return
	}

	out = gstr.SplitAndTrim(raw, "\n")

	for i, trim := range out {
		if gstr.HasPrefix(trim, "*") {
			old := out[0]
			out[0] = gstr.SubStr(trim, 2)
			if i != 0 {
				out[i] = old
			}
			break
		}
	}

	return
}

func (s *sGit) status(ctx context.Context) (out map[string][]string, err error) {
	out = make(map[string][]string)

	out[statusStaged] = []string{}
	out[statusChanged] = []string{}
	out[statusUntracked] = []string{}

	raw, err := gproc.ShellExec(ctx, "git status")
	if err != nil {
		return
	}

	trims := gstr.SplitAndTrim(raw, "\n")

	// 记录状态
	state := ""
	for _, trim := range trims {
		if gstr.HasPrefix(trim, "Changes to be committed") {
			s.log().Print(ctx, "未提交修改:")
			state = statusStaged
			continue
		} else if gstr.HasPrefix(trim, "Changes not staged for commit") {
			s.log().Print(ctx, "未暂存修改:")
			state = statusChanged
			continue
		} else if gstr.HasPrefix(trim, "Untracked files") {
			s.log().Print(ctx, "未跟踪修改:")
			state = statusUntracked
			continue
		}

		if len(trim) == 0 {
			state = ""
			continue
		}

		if !g.IsEmpty(state) {
			if !gstr.HasPrefix(trim, "(") {
				out[state] = append(out[state], trim)
				s.log().Print(ctx, trim)
			}
		}
	}
	return
}

// 创建二进制文件
const createBundleTpl = "git bundle create {{.Path}} {{.Branch}}"

func (s *sGit) createBundle(ctx context.Context, in *model.BundleConfigInput) (err error) {

	content, err := ysview.GViewNull().ParseContent(context.TODO(), consts.TmpPath+"/{{.Project}}-{{.Branch}}-{{.Date}}.bundle", gconv.Map(in))
	if err != nil {
		return
	}

	dir := gfile.Dir(content)
	if !gfile.Exists(dir) {
		err = gfile.Mkdir(dir)
		if err != nil {
			return
		}
	}

	in.Path = gfile.Abs(content)
	s.log().Print(ctx, "- 生成二进制文件: ", in.Path)
	cmd, _ := ysview.GViewNull().ParseContent(context.TODO(), createBundleTpl, gconv.Map(in))
	s.log().Debug(ctx, cmd)
	err = yslog.ShellRun(ctx, cmd)
	return
}

const cloneBundleTpl = "git clone -b {{.Branch}} {{.Path}} {{.ProjectPath}}"

func (s *sGit) cloneBundle(ctx context.Context, in *model.BundleConfigInput) (err error) {

	projectPath := in.Project
	i := 0
	for gfile.Exists(projectPath) {
		projectPath = in.Project + "(" + gconv.String(i) + ")"
		i++
	}

	projectPath = gfile.Abs(projectPath)

	s.log().Print(ctx, "- 克隆项目到：", projectPath)
	cmd, _ := ysview.GViewNull().ParseContent(context.TODO(), cloneBundleTpl, ysutils.MapStrAnyMix(
		gconv.Map(in),
		g.MapStrAny{
			"ProjectPath": projectPath,
		},
	))
	s.log().Debug(ctx, cmd)
	_ = gproc.ShellRun(ctx, cmd)

	// 切换工作路径到 可能有风险
	return os.Chdir(projectPath)
}

const createNewBranchAndCheckOutTpl = "git checkout {{.Branch}} -b {{.NewBranch}}"

func (s *sGit) createNewBranchAndCheckOut(ctx context.Context, in *model.BundleConfigInput) (err error) {
	s.log().Print(ctx, "- 切换到新分支")
	cmd, _ := ysview.GViewNull().ParseContent(context.TODO(), createNewBranchAndCheckOutTpl, gconv.Map(in))
	s.log().Debug(ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

const setOriginTpl = "git remote add origin {{.Path}}"

func (s *sGit) setOrigin(ctx context.Context, in *model.BundleConfigInput) error {
	s.log().Print(ctx, "- 设置远端为：", in.Path)
	cmd, _ := ysview.GViewNull().ParseContent(ctx, setOriginTpl, gconv.Map(in))
	s.log().Debug(ctx, "git remote rm origin")
	err := gproc.ShellRun(ctx, "git remote rm origin")
	if err != nil {
		return err
	}
	s.log().Debug(ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

const checkOutTpl = "git checkout {{.Branch}}"

func (s *sGit) checkOut(ctx context.Context, in *model.BundleConfigInput) error {
	s.log().Print(ctx, "- 切换分支：", in.Branch)
	cmd, _ := ysview.GViewNull().ParseContent(ctx, checkOutTpl, gconv.Map(in))
	s.log().Debug(ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

const pullTpl = "git pull origin {{.Branch}} --allow-unrelated-histories"

func (s *sGit) pull(ctx context.Context, in *model.BundleConfigInput) error {
	s.log().Print(ctx, "- 拉取")
	cmd, _ := ysview.GViewNull().ParseContent(context.TODO(), pullTpl, gconv.Map(in))
	s.log().Debug(ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

const mergeTpl = "git merge remotes/origin/{{.Branch}}"

func (s *sGit) merge(ctx context.Context, in *model.BundleConfigInput) error {
	s.log().Print(ctx, "- 合并远端分支到当前分支")
	cmd, _ := ysview.GViewNull().ParseContent(context.TODO(), mergeTpl, gconv.Map(in))
	s.log().Debug(ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

// 更新远端
const remoteUpdateTpl = "git remote update"

func (s *sGit) remoteUpdate(ctx context.Context) error {
	s.log().Print(ctx, "- 更新远端")
	cmd := remoteUpdateTpl
	s.log().Debug(ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

// 清理远端
const remotePruneTpl = "git remote prune origin"

func (s *sGit) RemotePrune(ctx context.Context, in *model.BundleConfigInput) error {
	s.log().Print(ctx, "- 清理远端")
	cmd, _ := ysview.GViewNull().ParseContent(ctx, remotePruneTpl, gconv.Map(in))
	s.log().Debug(ctx, ctx, cmd)
	return gproc.ShellRun(ctx, cmd)
}

//func GitPreStash() bool {
//
//	return true
//}
//
//func GitStatus() (out map[string][]string) {
//	out = make(map[string][]string)
//
//	out["commited"] = []string{}
//	out["changed"] = []string{}
//	out["unstaged"] = []string{}
//
//	raw, err := gproc.ShellExec("git status")
//	if err != nil {
//		return nil
//	}
//
//	trims := gstr.SplitAndTrim(raw, "\n")
//
//	state := ""
//	for _, trim := range trims {
//		if gstr.HasPrefix(trim, "Changes to be committed") {
//			s.log().Print("未提交修改:")
//			state = "commited"
//			continue
//		} else if gstr.HasPrefix(trim, "Changes not staged for commit") {
//			s.log().Print("未贮藏修改:")
//			state = "changed"
//			continue
//		} else if gstr.HasPrefix(trim, "Untracked files") {
//			s.log().Print("未跟踪修改:")
//			state = "unstaged"
//			continue
//		}
//
//		if len(trim) == 0 {
//			state = ""
//			continue
//		}
//
//		if !g.IsEmpty(state) {
//			if !gstr.HasPrefix(trim, "(") {
//				out[state] = append(out[state], trim)
//				s.log().Print(trim)
//			}
//		}
//	}
//	return
//}
//
//const cloneTpl = "git clone -b {{.Branch}} {{.Path}} {{.ProjectPath}}"
//
//func GitCmdClone(param g.MapStrAny) {
//
//	projectPath := param["Project"].(string)
//	i := 0
//	for gfile.Exists(projectPath) {
//		projectPath = param["Project"].(string) + "(" + gconv.String(i) + ")"
//		i++
//	}
//
//	param["ProjectPath"] = gfile.Abs(projectPath)
//
//	s.log().Print("- 克隆项目到：", param["ProjectPath"])
//	cmd, _ := GViewNull().ParseContent(context.TODO(), cloneTpl, param)
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//
//	// 切换工作路径到 可能有风险
//	os.Chdir(param["ProjectPath"].(string))
//}
//
//const checkOutTpl = "git checkout {{.Branch}}"
//
//func GitCmdCheckOut(param g.MapStrAny) {
//
//	s.log().Print("- 切换分支：", param["Branch"])
//	cmd, _ := GViewNull().ParseContent(context.TODO(), checkOutTpl, param)
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
//
//const setOriginTpl = "git remote add origin {{.Path}}"
//const setUpstream = "git branch --set-upstream-to=origin/{{.Branch}} {{.Branch}}"
//
//func GitCmdSetOrigin(param g.MapStrAny) {
//	s.log().Print("- 设置远端为：", param["Path"])
//	cmd, _ := GViewNull().ParseContent(context.TODO(), setOriginTpl, param)
//	s.log().Debug("git remote rm origin")
//	gproc.ShellRun("git remote rm origin")
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
//
//const createNewBranchAndCheckOutTpl = "git checkout {{.Branch}} -b {{.NewBranch}}"
//
//func GitCmdCreateNewBranchAndCheckOut(param g.MapStrAny) {
//	s.log().Print("- 切换到新分支")
//	cmd, _ := GViewNull().ParseContent(context.TODO(), createNewBranchAndCheckOutTpl, param)
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
//
//const pullTpl = "git pull origin {{.Branch}} --allow-unrelated-histories"
//
//func GitCmdPull(param g.MapStrAny) {
//	s.log().Print("- 拉取")
//	cmd, _ := GViewNull().ParseContent(context.TODO(), pullTpl, param)
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
//

//
//// 更新远端
//const remoteUpdateTpl = "git remote update"
//
//func GitCmdRemoteUpdate() {
//	s.log().Print("- 更新远端")
//	cmd := remoteUpdateTpl
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
//
//// 清理远端
//const remotePruneTpl = "git remote prune \"origin\""
//
//func GitCmdRemotePrune(param g.MapStrAny) {
//	s.log().Print("- 清理远端")
//	cmd, _ := GViewNull().ParseContent(context.TODO(), remotePruneTpl, param)
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
//
//// 命令模板
//const mergeTpl = "git merge remotes/origin/{{.Branch}}"
//
//func GitCmdMerge(param g.MapStrAny) {
//	s.log().Print("- 合并远端分支到当前分支")
//	cmd, _ := GViewNull().ParseContent(context.TODO(), mergeTpl, param)
//	s.log().Debug(cmd)
//	_ = gproc.ShellRun(cmd)
//}
